package com.scexample.builder;

import com.alibaba.dubbo.config.annotation.Reference;
import com.scexample.service.MerchantService;
import com.scexample.template.PayMerchantTemplate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @program: scm-base-service15
 * @description: 商户进件工具
 * @author: 少男
 * @create: 2021-01-20 13:44
 **/
@Configuration
@ConditionalOnClass(ApplicationContext.class)
@AutoConfigureAfter(value = {ApplicationContext.class})
public class PayMerchantBuilder implements ApplicationContextAware, BeanFactoryAware {

    private ApplicationContext applicationContext;

    private ListableBeanFactory listableBeanFactory;

    /**预热加载要调用的dubbo服务接口，调用方相应做降级处理*/
    @Reference(group = "", version = "1.0", mock = "com.scexample.mock.MerchantServiceMock")
    private MerchantService merchantService;

    @Bean("scTemplateBuilder")
    public TemplateBuilder templateBuilder() {
        return new TemplateBuilder(this.applicationContext);
    }

    /**
     * <p>构建业务模板对象（可扩展）
     * <p>三种build方式可选</p>
     * <p>// 1.只根据支付类型来确定最终业务执行模板 （通过spring上下文找支付中台业务对象引用，效率较慢）
     * // 优点：可以独立于MerchantApplyBuilder.class之外任意地方使用
     * return templateBuilder.build(payCode).getPayMerchantTemplate();</p>
     * <p>// 2.根据支付类型及支付中台业务处理对象获取业务执行模板（直接赋值，效率基本与方法3一致）
     * return templateBuilder.build(payCode, merchantService).getPayMerchantTemplate();
     * return templateBuilder.build(payCode, MerchantService.class).getPayMerchantTemplate();
     * 支持只传payCode，build过程中支持自动从上下文找寻引用业务service并注入
     * return templateBuilder.build(payCode).getPayMerchantTemplate();</p>
     * <p>// 3.(此方式作废，已将payCode置为私有内部使用)通过两次build属性来确定最终业务执行模板（等同于方法2，创建步骤较为繁琐）
     * return templateBuilder.payCode(payCode, merchantService).build().getPayMerchantTemplate();</p>
     * @param payCode 支付类型(必传)
     * @return 组装好的业务模板对象
     *
     */
    public PayMerchantTemplate build(Byte payCode) {
//        TemplateBuilder templateBuilder = BeanFactoryUtils.beanOfType(listableBeanFactory, TemplateBuilder.class);
        return applicationContext.getBean("scTemplateBuilder", TemplateBuilder.class).build(payCode, merchantService).getPayMerchantTemplate();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        listableBeanFactory = (ListableBeanFactory) beanFactory;
    }
}
